perm filename APP3.TEX[UHF,DEK] blob sn#841394 filedate 1987-01-28 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00008 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	% (macros edited from TWIMAC)
C00026 00003	\pageno=14
C00031 00004	\N5.  The character set.
C00039 00005	\N10.  Inputting the data.
C00043 00006	\N14.  Pixel compensation.
C00055 00007	\N23.  The main program.
C00056 00008	\message{app4 is next (and last!)}
C00061 ENDMK
C⊗;
% (macros edited from TWIMAC)
\newdimen\em \em=10pt
\parskip 0pt % no stretch between paragraphs
\parindent 1\em % for paragraphs and for the first line of Pascal text

\font\manual=manfnt
\font\ninerm=cmr9
\font\eightrm=cmr8
\font\sixrm=cmr6
\font\ninei=cmmi9
\font\eighti=cmmi8
\font\sixi=cmmi6
\skewchar\ninei='177 \skewchar\eighti='177 \skewchar\sixi='177
\font\ninesy=cmsy9
\font\eightsy=cmsy8
\font\sixsy=cmsy6
\skewchar\ninesy='60 \skewchar\eightsy='60 \skewchar\sixsy='60
\font\ninebf=cmbx9
\font\eightbf=cmbx8
\font\sixbf=cmbx6
\font\ninett=cmtt9
\font\eighttt=cmtt8
\hyphenchar\ninett=-1 \hyphenchar\eighttt=-1
\font\ninesl=cmsl9
\font\eightsl=cmsl8
\font\nineit=cmti9
\font\eightit=cmti8

\newif\iftenpoint
\def\tenpoint{\tenpointtrue
 \def\rm{\fam0\tenrm}%
  \textfont0=\tenrm \scriptfont0=\sevenrm \scriptscriptfont0=\fiverm
  \textfont1=\teni \scriptfont1=\seveni \scriptscriptfont1=\fivei
  \textfont2=\tensy \scriptfont2=\sevensy \scriptscriptfont2=\fivesy
  \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
  \def\it{\fam\itfam\tenit}%
  \textfont\itfam=\tenit
  \def\sl{\fam\slfam\tensl}%
  \textfont\slfam=\tensl
  \def\bf{\fam\bffam\tenbf}%
  \textfont\bffam=\tenbf \scriptfont\bffam=\sevenbf
   \scriptscriptfont\bffam=\fivebf
  \def\tt{\fam\ttfam\tentt}%
  \textfont\ttfam=\tentt
  \def\ttx{\tentex}%
  \normalbaselineskip=12pt
  \def\MF{{\manual META}\-{\manual FONT}}%
  \let\sc=\eightrm
  \let\big=\tenbig
  \setbox\strutbox=\hbox{\vrule height8pt depth3pt width 0pt}%
  \normalbaselines\rm}

\def\ninepoint{\tenpointfalse
 \def\rm{\fam0\ninerm}%
  \textfont0=\ninerm \scriptfont0=\sixrm \scriptscriptfont0=\fiverm
  \textfont1=\ninei \scriptfont1=\sixi \scriptscriptfont1=\fivei
  \textfont2=\ninesy \scriptfont2=\sixsy \scriptscriptfont2=\fivesy
  \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
  \def\it{\fam\itfam\nineit}%
  \textfont\itfam=\nineit
  \def\sl{\fam\slfam\ninesl}%
  \textfont\slfam=\ninesl
  \def\bf{\fam\bffam\ninebf}%
  \textfont\bffam=\ninebf \scriptfont\bffam=\sixbf
   \scriptscriptfont\bffam=\fivebf
  \def\tt{\fam\ttfam\ninett}%
  \textfont\ttfam=\ninett
  \def\ttx{\ninetex}%
  \normalbaselineskip=11pt
  \def\MF{{\manual hijk}\-{\manual lmnj}}%
  \let\sc=\sevenrm
  \let\big=\ninebig
  \setbox\strutbox=\hbox{\vrule height8pt depth3pt width 0pt}%
  \normalbaselines\rm}

\def\eightpoint{%
 \def\rm{\fam0\eightrm}%
  \textfont0=\eightrm \scriptfont0=\sixrm \scriptscriptfont0=\fiverm
  \textfont1=\eighti \scriptfont1=\sixi \scriptscriptfont1=\fivei
  \textfont2=\eightsy \scriptfont2=\sixsy \scriptscriptfont2=\fivesy
  \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
  \def\it{\fam\itfam\eightit}%
  \textfont\itfam=\eightit
  \def\sl{\fam\slfam\eightsl}%
  \textfont\slfam=\eightsl
  \def\bf{\fam\bffam\eightbf}%
  \textfont\bffam=\eightbf \scriptfont\bffam=\sixbf
   \scriptscriptfont\bffam=\fivebf
  \def\tt{\fam\ttfam\eighttt}%
  \textfont\ttfam=\eighttt
  \def\ttx{\eighttex}%
  \normalbaselineskip=9pt
  \def\MF{{\manual opqr}\-{\manual stuq}}%
  \let\sc=\sixrm
  \let\big=\eightbig
  \setbox\strutbox=\hbox{\vrule height7pt depth2pt width 0pt}%
  \normalbaselines\rm}

\def\tenbig#1{{\hbox{$\left#1\vbox to8.5pt{}\right.\nulldelimiterspace=0pt$}}}
\def\ninebig#1{{\hbox{$\textfont0=\tenrm\textfont2=\tensy
  \left#1\vbox to7.25pt{}\right.\nulldelimiterspace=0pt$}}}
\def\eightbig#1{{\hbox{$\textfont0=\ninerm\textfont2=\ninesy
  \left#1\vbox to6.5pt{}\right.\nulldelimiterspace=0pt$}}}

\font\tentex=cmtex10
\font\ninetex=cmtex9 % TeX extended character set (used in strings)
\font\eighttex=cmtex8

\def\\#1{\hbox{\it#1\/\kern.05em}} % italic type for identifiers
\def\|#1{\hbox{$#1$}} % one-letter identifiers look a bit better this way
\def\{\hbox{\bf#1\/}} % boldface type for reserved words
\def\.#1{\hbox{\ttx % typewriter type for strings
  \let\\=\BS % backslash in a string
  \let\'=\RQ % right quote in a string
  \let\`=\LQ % left quote in a string
  \let\{=\LB % left brace in a string
  \let\}=\RB % right brace in a string
  \let\~=\TL % tilde in a string
  \let\ =\SP % space in a string
  \let\_=\UL % underline in a string
  \let\&=\AM % ampersand in a string
  #1}}
\def\#{\hbox{\tt\char`\#}} % parameter sign
\def\${\hbox{\tt\char`\$}} % dollar sign
\def\%{\hbox{\tt\char`\%}} % percent sign
\def\↑{\ifmmode\mathchar"222 \else\char`↑ \fi} % pointer or hat
% circumflex accents can be obtained from \↑↑D instead of \↑
\def\AT!{@} % at sign for control text

\chardef\AM=`\& % ampersand character in a string
\chardef\BS=`\\ % backslash in a string
\chardef\LB=`\{ % left brace in a string
\def\LQ{{\tt\char'22}} % left quote in a string
\chardef\RB=`\} % right brace in a string
\def\RQ{{\tt\char'23}} % right quote in a string
\def\SP{{\tt\char`\ }} % (visible) space in a string
\chardef\TL=`\~ % tilde in a string
\chardef\UL=`\_ % underline character in a string

\newbox\bak \setbox\bak=\hbox to -\em{} % backspace one em
\newbox\bakk\setbox\bakk=\hbox to -2\em{} % backspace two ems

\newcount\ind % current indentation in ems
\def\1{\global\advance\ind by1\hangindent\ind\em} % indent one more notch
\def\2{\global\advance\ind by-1} % indent one less notch
\def\3#1{\hfil\penalty#10\hfilneg} % optional break within a statement
\def\4{\copy\bak} % backspace one notch
\def\5{\hfil\penalty-1\hfilneg\kern2.5\em\copy\bakk\ignorespaces}%optional break
\def\6{\ifmmode\else\par % forced break
  \hangindent\ind\em\noindent\kern\ind\em\copy\bakk\ignorespaces\fi}
\def\7{\Y\6} % forced break and a little extra space

\let\yskip=\smallskip
\def\to{\mathrel{.\,.}} % double dot, used only in math mode
\def\ellipsis{\kern5\em\smash{\vdots}\qquad\vbox to12pt{}\par}
\def\note#1#2.{\par\penalty5000
  \Y\noindent{\hangindent2\em\baselineskip10pt\eightrm#1 #2.\par}}
\def\startsection{\vskip0pt plus 100pt \penalty-100
  \vskip12pt plus-100pt minus 3pt\Q\noindent\strut{\bf\modno.\quad}\iftrue}
\def\defin#1{\global\advance\ind by 2 \1\&{#1 }} % begin `define' or `format'
\def\A{\note{See also}} % cross-reference for multiply defined section names
\def\B{\mathopen{\.{@\{}}} % begin controlled comment
\def\C#1{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % Pascal comments
  \XX\hfil\penalty-1\hfilneg\quad$\{\,$#1$\,\}$\XX}
\def\D{\defin{define}} % macro definition
\def\E{\cdot10↑} % exponent in floating point constant
\def\F{\defin{format}} % format definition
\let\G=\ge % greater than or equal sign
\def\H#1{\hbox{\rm\char"7D\tt#1}} % hexadecimal constant
\let\I=\ne % unequal sign
\def\J{\.{@\&}} % TANGLE's join operation
\let\K=\gets % left arrow
\let\L=\le % less than or equal sign
\outer\def\M#1.{\def\modno{#1}\startsection\ignorespaces}
\outer\def\N#1. #2.{\def\modno{#1}%
  \startsection{\bf\ignorespaces#2.\quad}\ignorespaces}
\def\O#1{\hbox{\rm\char'23\kern-.2em\it#1\/\kern.05em}} % octal constant
\def\P{\iftenpoint \ninepoint\fi
  \rightskip=0pt plus 100pt minus 10pt % go into Pascal mode
  \sfcode`;=3000
  \pretolerance 10000
  \hyphenpenalty 10000 \exhyphenpenalty 10000
  \global\ind=2 \1\ \unskip}
\def\Q{\tenpoint
  \rightskip=0pt % get out of Pascal mode
  \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 }
\let\R=\lnot % logical not
\let\S=\equiv % equivalence sign
\def\T{\mathclose{\.{@\}}}} % terminate controlled comment
\def\U{\note{This code is used in}} % cross-reference for uses of sections
\let\V=\lor % logical or
\let\W=\land % logical and
\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name
  \XX$\langle\,$#2{\sevenrm\kern.5em#1}$\,\rangle$\XX}
\def\Y{\par\yskip}
\let\Z=\let % now you can \send the control sequence \Z
\def\){\hbox{\.{@\$}}} % sign for string pool check sum
\def\]{\hbox{\.{@\\}}} % sign for forced line break
\def\=#1{\kern2pt\hbox{\vrule\vtop{\vbox{\hrule
        \hbox{\strut\kern2pt\.{#1}\kern2pt}}
      \hrule}\vrule}\kern2pt} % verbatim string
\let\~=\ignorespaces

\pageno=14
\noindent\strut{\bf Appendix 3: Transforming the pixel data}
\vskip 1pt plus 1pt
\noindent The following {\tt WEB} program illustrates how to
convert data like that of Appendix~1 into the form required by the
fonts and macros described earlier.

\N1.  Introduction.
This program prepares 33-level halftone images for use in \TeX\ files. The
input is assumed to be a sequence of pictures expressed in the form
$$\halign{\qquad#\hfil\cr
$m\quad n$\cr
$\langle\,$first line of pixel data, $n$ characters long$\,\rangle$\cr
\ \ \ \dots\cr
$\langle\,m$th line of pixel data, $n$ characters long$\,\rangle$\cr}$$
terminated by a line that says simply `\.0'.
The pixel data consists of the characters \.{"0"} to~\.{"9"} and
\.{"A"} to~\.{"V"}, representing 32 levels of darkness from black to white.
[See Appendix~1.]

The output is the same set of pictures, expressed in a simple format used
for 33-level halftones, with ASCII characters \.{"0"} to \.{"P"} representing
darkness levels from white to black. The levels are adjusted to compensate
for the idiosyncrasies of Canon {\ninerm LBP-CX} laser-printing engines.
Two dots are typeset for each pixel of input; hence there are $2m$
``half\/lines'' of $n$-character data in the output.

\fi

\M2. Here's an outline of the entire Pascal program:

\Y\P\4\&{program}\1\  \37$\\{halftones}(\\{input},\39\\{output})$;\6
\4\&{label} \37\X4:Labels in the outer block\X\6
\4\&{const} \37\X3:Constants in the outer block\X\6
\4\&{type} \37\X5:Types in the outer block\X\6
\4\&{var} \37\X6:Global variables\X\7
\4\&{procedure}\1\  \37\\{initialize};\C{this procedure gets things started
properly}\6
\4\&{var} \37\X8:Local variables for initialization\X\2\6
\&{begin} \37\X7:Set initial values\X\6
\&{end};\7
\&{begin} \37\\{initialize};\5
\X23:The main program\X;\6
\&{end}.\par
\fi

\M3. Each picture in the input data must contain fewer than \\{max\_m} rows and
\\{max\_n} columns.

\Y\P$\4\X3:Constants in the outer block\X\S$\6
$\\{max\_m}=200$;\C{$m$ should be less than this}\6
$\\{max\_n}=200$;\C{$n$ should be less than this}\par
\U section~2.\fi

\M4. The main program has one statement label, namely \\{cleanup\_and%
\_terminate}.

\Y\P\D \37$\\{cleanup\_and\_terminate}=9998$\par
\P\D \37$\\{finish}\S$\1\5
\&{goto} \37\\{cleanup\_and\_terminate}\C{do this when all the pictures have
been output}\2\par
\Y\P$\4\X4:Labels in the outer block\X\S$\6
\\{cleanup\_and\_terminate};\par
\U section~2.\fi

\N5.  The character set.
We need translation tables between ASCII and the actual character
set, in order to make this program portable. The standard conventions of
{\sl \TeX: The Program\/} are copied here, essentially verbatim.

\Y\P\D \37$\\{text\_char}\S\\{char}$\C{the data type of characters in text
files}\par
\P\D \37$\\{first\_text\_char}=0$\C{ordinal number of the smallest element of %
\\{text\_char}}\par
\P\D \37$\\{last\_text\_char}=127$\C{ordinal number of the largest element of %
\\{text\_char}}\par
\Y\P$\4\X5:Types in the outer block\X\S$\6
$\\{ASCII\_code}=0\to127$;\C{seven-bit numbers}\par
\U section~2.\fi

\M6. \P$\X6:Global variables\X\S$\6
\4\\{xord}: \37\&{array} $[\\{text\_char}]$ \1\&{of}\5
\\{ASCII\_code};\C{specifies conversion of input characters}\2\6
\4\\{xchr}: \37\&{array} $[\\{ASCII\_code}]$ \1\&{of}\5
\\{text\_char};\C{specifies conversion of output characters}\2\par
\A sections~10, 13, 14, and~22.
\U section~2.\fi

\M7. \P$\X7:Set initial values\X\S$\6
$\\{xchr}[\O{40}]\K\.{\'\ \'}$;\5
$\\{xchr}[\O{41}]\K\.{\'!\'}$;\5
$\\{xchr}[\O{42}]\K\.{\'"\'}$;\5
$\\{xchr}[\O{43}]\K\.{\'\#\'}$;\5
$\\{xchr}[\O{44}]\K\.{\'\$\'}$;\5
$\\{xchr}[\O{45}]\K\.{\'\%\'}$;\5
$\\{xchr}[\O{46}]\K\.{\'\&\'}$;\5
$\\{xchr}[\O{47}]\K\.{\'\'}\.{\'\'}$;\6
$\\{xchr}[\O{50}]\K\.{\'(\'}$;\5
$\\{xchr}[\O{51}]\K\.{\')\'}$;\5
$\\{xchr}[\O{52}]\K\.{\'*\'}$;\5
$\\{xchr}[\O{53}]\K\.{\'+\'}$;\5
$\\{xchr}[\O{54}]\K\.{\',\'}$;\5
$\\{xchr}[\O{55}]\K\.{\'-\'}$;\5
$\\{xchr}[\O{56}]\K\.{\'.\'}$;\5
$\\{xchr}[\O{57}]\K\.{\'/\'}$;\6
$\\{xchr}[\O{60}]\K\.{\'0\'}$;\5
$\\{xchr}[\O{61}]\K\.{\'1\'}$;\5
$\\{xchr}[\O{62}]\K\.{\'2\'}$;\5
$\\{xchr}[\O{63}]\K\.{\'3\'}$;\5
$\\{xchr}[\O{64}]\K\.{\'4\'}$;\5
$\\{xchr}[\O{65}]\K\.{\'5\'}$;\5
$\\{xchr}[\O{66}]\K\.{\'6\'}$;\5
$\\{xchr}[\O{67}]\K\.{\'7\'}$;\6
$\\{xchr}[\O{70}]\K\.{\'8\'}$;\5
$\\{xchr}[\O{71}]\K\.{\'9\'}$;\5
$\\{xchr}[\O{72}]\K\.{\':\'}$;\5
$\\{xchr}[\O{73}]\K\.{\';\'}$;\5
$\\{xchr}[\O{74}]\K\.{\'<\'}$;\5
$\\{xchr}[\O{75}]\K\.{\'=\'}$;\5
$\\{xchr}[\O{76}]\K\.{\'>\'}$;\5
$\\{xchr}[\O{77}]\K\.{\'?\'}$;\6
$\\{xchr}[\O{100}]\K\.{\'@\'}$;\5
$\\{xchr}[\O{101}]\K\.{\'A\'}$;\5
$\\{xchr}[\O{102}]\K\.{\'B\'}$;\5
$\\{xchr}[\O{103}]\K\.{\'C\'}$;\5
$\\{xchr}[\O{104}]\K\.{\'D\'}$;\5
$\\{xchr}[\O{105}]\K\.{\'E\'}$;\5
$\\{xchr}[\O{106}]\K\.{\'F\'}$;\5
$\\{xchr}[\O{107}]\K\.{\'G\'}$;\6
$\\{xchr}[\O{110}]\K\.{\'H\'}$;\5
$\\{xchr}[\O{111}]\K\.{\'I\'}$;\5
$\\{xchr}[\O{112}]\K\.{\'J\'}$;\5
$\\{xchr}[\O{113}]\K\.{\'K\'}$;\5
$\\{xchr}[\O{114}]\K\.{\'L\'}$;\5
$\\{xchr}[\O{115}]\K\.{\'M\'}$;\5
$\\{xchr}[\O{116}]\K\.{\'N\'}$;\5
$\\{xchr}[\O{117}]\K\.{\'O\'}$;\6
$\\{xchr}[\O{120}]\K\.{\'P\'}$;\5
$\\{xchr}[\O{121}]\K\.{\'Q\'}$;\5
$\\{xchr}[\O{122}]\K\.{\'R\'}$;\5
$\\{xchr}[\O{123}]\K\.{\'S\'}$;\5
$\\{xchr}[\O{124}]\K\.{\'T\'}$;\5
$\\{xchr}[\O{125}]\K\.{\'U\'}$;\5
$\\{xchr}[\O{126}]\K\.{\'V\'}$;\5
$\\{xchr}[\O{127}]\K\.{\'W\'}$;\6
$\\{xchr}[\O{130}]\K\.{\'X\'}$;\5
$\\{xchr}[\O{131}]\K\.{\'Y\'}$;\5
$\\{xchr}[\O{132}]\K\.{\'Z\'}$;\5
$\\{xchr}[\O{133}]\K\.{\'[\'}$;\5
$\\{xchr}[\O{134}]\K\.{\'\\\'}$;\5
$\\{xchr}[\O{135}]\K\.{\']\'}$;\5
$\\{xchr}[\O{136}]\K\.{\'\↑\'}$;\5
$\\{xchr}[\O{137}]\K\.{\'\_\'}$;\6
$\\{xchr}[\O{140}]\K\.{\'\`\'}$;\5
$\\{xchr}[\O{141}]\K\.{\'a\'}$;\5
$\\{xchr}[\O{142}]\K\.{\'b\'}$;\5
$\\{xchr}[\O{143}]\K\.{\'c\'}$;\5
$\\{xchr}[\O{144}]\K\.{\'d\'}$;\5
$\\{xchr}[\O{145}]\K\.{\'e\'}$;\5
$\\{xchr}[\O{146}]\K\.{\'f\'}$;\5
$\\{xchr}[\O{147}]\K\.{\'g\'}$;\6
$\\{xchr}[\O{150}]\K\.{\'h\'}$;\5
$\\{xchr}[\O{151}]\K\.{\'i\'}$;\5
$\\{xchr}[\O{152}]\K\.{\'j\'}$;\5
$\\{xchr}[\O{153}]\K\.{\'k\'}$;\5
$\\{xchr}[\O{154}]\K\.{\'l\'}$;\5
$\\{xchr}[\O{155}]\K\.{\'m\'}$;\5
$\\{xchr}[\O{156}]\K\.{\'n\'}$;\5
$\\{xchr}[\O{157}]\K\.{\'o\'}$;\6
$\\{xchr}[\O{160}]\K\.{\'p\'}$;\5
$\\{xchr}[\O{161}]\K\.{\'q\'}$;\5
$\\{xchr}[\O{162}]\K\.{\'r\'}$;\5
$\\{xchr}[\O{163}]\K\.{\'s\'}$;\5
$\\{xchr}[\O{164}]\K\.{\'t\'}$;\5
$\\{xchr}[\O{165}]\K\.{\'u\'}$;\5
$\\{xchr}[\O{166}]\K\.{\'v\'}$;\5
$\\{xchr}[\O{167}]\K\.{\'w\'}$;\6
$\\{xchr}[\O{170}]\K\.{\'x\'}$;\5
$\\{xchr}[\O{171}]\K\.{\'y\'}$;\5
$\\{xchr}[\O{172}]\K\.{\'z\'}$;\5
$\\{xchr}[\O{173}]\K\.{\'\{\'}$;\5
$\\{xchr}[\O{174}]\K\.{\'|\'}$;\5
$\\{xchr}[\O{175}]\K\.{\'\}\'}$;\5
$\\{xchr}[\O{176}]\K\.{\'\~\'}$;\6
$\\{xchr}[0]\K\.{\'\ \'}$;\5
$\\{xchr}[\O{177}]\K\.{\'\ \'}$;\C{ASCII codes 0 and \O{177} do not appear in
text}\par
\A sections~9, 11, 15, and~17.
\U section~2.\fi

\M8. \P$\X8:Local variables for initialization\X\S$\6
\4\|i: \37$0\to\\{last\_text\_char}$;\par
\U section~2.\fi

\M9. \P$\X7:Set initial values\X\mathrel{+}\S$\6
\&{for} $\|i\K1\mathrel{\&{to}}\O{37}$ \1\&{do}\5
$\\{xchr}[\|i]\K\.{\'\ \'}$;\2\6
\&{for} $\|i\K\\{first\_text\_char}\mathrel{\&{to}}\\{last\_text\_char}$ \1%
\&{do}\5
$\\{xord}[\\{chr}(\|i)]\K\O{177}$;\2\6
\&{for} $\|i\K1\mathrel{\&{to}}\O{176}$ \1\&{do}\5
$\\{xord}[\\{xchr}[\|i]]\K\|i$;\2\par
\fi

\N10.  Inputting the data.
We keep the pixel values in a big global array called \|v.
The variables \|m and~\|n keep track of the current number of rows
and columns in use.

The \\{dd} table contains density values assumed for the input,
indexed by single-character codes.

\Y\P$\4\X6:Global variables\X\mathrel{+}\S$\6
\4\|v: \37\&{array} $[0\to\\{max\_m},\390\to\\{max\_n}]$ \1\&{of}\5
\\{real};\C{pixel darknesses, from 0.0 to 1.0}\2\6
\4\|m: \37\\{integer};\C{rows $0\to\|m+1$ of \|v should contain relevant data}\6
\4\|n: \37\\{integer};\C{columns $0\to\|n+1$ of \|v should contain relevant
data}\6
\4\\{dd}: \37\&{array} $[\\{text\_char}]$ \1\&{of}\5
\\{real};\2\par
\fi

\M11. All input codes give zero density, except \.{"0"} to~\.{"9"} and
\.{"A"} to \.{"V"}.

\Y\P$\4\X7:Set initial values\X\mathrel{+}\S$\6
\&{for} $\|i\K\\{first\_text\_char}\mathrel{\&{to}}\\{last\_text\_char}$ \1%
\&{do}\5
$\\{dd}[\\{chr}(\|i)]\K0.0$;\2\6
\&{for} $\|i\K\.{"0"}\mathrel{\&{to}}\.{"9"}$ \1\&{do}\5
$\\{dd}[\\{chr}(\|i)]\K1.0-(\|i-\.{"0"})/31.0$;\2\6
\&{for} $\|i\K\.{"A"}\mathrel{\&{to}}\.{"V"}$ \1\&{do}\5
$\\{dd}[\\{chr}(\|i)]\K1.0-(\|i-\.{"A"}+10)/31.0$;\2\par
\fi

\M12. The process of inputting pixel values is quite simple. We terminate the
program if anomalous values of \|m and~\|n occur. Boundary values are added
at the top, left, right, and bottom in order to provide ``padding'' that
will be convenient in the pixel transformation process. Each boundary value
is equal to one of its adjacent neighbors.

\Y\P$\4\X12:Input a picture, or terminate the program\X\S$\6
$\\{read}(\|m)$;\ \&{if} $(\|m\L0)\V(\|m\G\\{max\_m})$ \1\&{then}\5
\\{finish};\2\6
$\\{read\_ln}(\|n)$;\ \&{if} $(\|n\L0)\V(\|n\G\\{max\_n})$ \1\&{then}\5
\\{finish};\2\6
\&{for} $\|i\K1\mathrel{\&{to}}\|m$ \1\&{do}\6
\&{begin} \37\&{for} $\|j\K1\mathrel{\&{to}}\|n$ \1\&{do}\6
\&{begin} \37$\\{read}(\|c)$;\5
$\|v[\|i,\39\|j]\K\\{dd}[\|c]$;\6
\&{end};\2\6
$\|v[\|i,\390]\K\|v[\|i,\391]$;\5
$\|v[\|i,\39\|n+1]\K\|v[\|i,\39\|n]$;\6
\\{read\_ln};\6
\&{end};\2\6
\&{for} $\|j\K0\mathrel{\&{to}}\|n+1$ \1\&{do}\6
\&{begin} \37$\|v[0,\39\|j]\K\|v[1,\39\|j]$;\5
$\|v[\|m+1,\39\|j]\K\|v[\|m,\39\|j]$;\6
\&{end}\2\par
\U section~23.\fi

\M13. The code just written makes use of three temporary registers that must
be declared:

\Y\P$\4\X6:Global variables\X\mathrel{+}\S$\6
\4$\|i,\39\|j$: \37\\{integer};\C{current row and column}\6
\4\|c: \37\\{char};\C{character read from input}\par
\fi

\N14.  Pixel compensation.
The 33-level output of this program is assumed to be printed by a font
that contains $4\times8$ characters, where each character has 0 to~32
black bits. Physical properties of output devices cause distortions,
so that a character with \|k black bits does not have an apparent
density of $\|k/32$. We therefore maintain a table of apparent density
values.

\Y\P\D \37$\\{max\_l}=32$\C{maximum output level}\par
\Y\P$\4\X6:Global variables\X\mathrel{+}\S$\6
\4\|d: \37\&{array} $[0\to\\{max\_l}]$ \1\&{of}\5
\\{real};\C{apparent densities, from 0.0 to 1.0}\2\par
\fi

\M15. This table is based on some densitometer measurements that are not
especially reliable. The amount of toner seems to vary between the top of
a page and the bottom; also blocks of the character \.{"N"} seem to appear
darker than blocks of the character \.{"O"}, because of some property of
xerography, although the \.{"O"} has one more bit turned on. Such
anomalies have been smoothed out here, since the resulting values should
prove good enough in practice.

\Y\P$\4\X7:Set initial values\X\mathrel{+}\S$\6
$\|d[0]\K0.0$;\5
$\|d[1]\K0.06$;\5
$\|d[2]\K0.095$;\5
$\|d[3]\K0.125$;\5
$\|d[4]\K0.155$;\6
$\|d[5]\K0.175$;\5
$\|d[6]\K0.215$;\5
$\|d[7]\K0.245$;\5
$\|d[8]\K0.27$;\5
$\|d[9]\K0.29$;\6
$\|d[10]\K0.3$;\5
$\|d[11]\K0.31$;\5
$\|d[12]\K0.32$;\5
$\|d[13]\K0.33$;\5
$\|d[14]\K0.34$;\6
$\|d[15]\K0.35$;\5
$\|d[16]\K0.36$;\5
$\|d[17]\K0.37$;\5
$\|d[18]\K0.38$;\5
$\|d[19]\K0.4$;\6
$\|d[20]\K0.42$;\5
$\|d[21]\K0.44$;\5
$\|d[22]\K0.47$;\5
$\|d[23]\K0.5$;\5
$\|d[24]\K0.53$;\6
$\|d[25]\K0.57$;\5
$\|d[26]\K0.61$;\5
$\|d[27]\K0.66$;\5
$\|d[28]\K0.72$;\5
$\|d[29]\K0.80$;\6
$\|d[30]\K0.88$;\5
$\|d[31]\K0.96$;\5
$\|d[32]\K1.0$;\par
\fi

\M16. We convert the pixel values by using a variant of the Floyd-Steinberg
algorithm for adaptive grayscale [Society for Information Display,
{\sl SID 75 Digest}, 36--37].
The idea is to find the best available density, then to diffuse the error
into adjacent pixels that haven't yet been processed.

The following code assumes that \|x is the desired density value
in column~\|j of the current half\/line.
It outputs one 33-level density,
then updates \|x and~\|j in preparation for the next column.
Adjustments to the densities in the two next half\/lines are
accumulated in auxiliary arrays \\{next1} and \\{next2}; this will compensate
for errors in the current half\/line.

We assume that $\\{next1}[\|j]$, $\\{next1}[\|j+1]$, and $\\{next2}[\|j]$
correspond to the
dots that are adjacent to $\\{current}[\|j]$.

\Y\P$\4\X16:Output one value and move to the next column\X\S$\6
\X21:Find \|l so that $\|d[\|l]$ is as close as possible to \|x\X;\6
$\\{write}(\\{xchr}[\.{"0"}+\|l])$;\5
$\\{err}\K\|x-\|d[\|l]$;\6
$\\{next1}[\|j]\K\\{next1}[\|j]+\\{alpha}\ast\\{err}$;\6
$\\{next2}[\|j]\K\\{beta}\ast\\{err}$;\6
$\|j\K\|j+1$;\C{move right}\6
$\\{next1}[\|j]\K\\{next1}[\|j]+\\{gamma}\ast\\{err}$;\6
$\|x\K\\{current}[\|j]+\\{delta}\ast\\{err}$\par
\U sections~18 and~18.\fi

\M17. The constants $\\{alpha}\to\\{delta}$ control the distribution of errors
to
adjacent dot positions.

\Y\P$\4\X7:Set initial values\X\mathrel{+}\S$\6
$\\{alpha}\K7/16$;\C{error diffusion to SW neighbor}\6
$\\{beta}\K1/16$;\C{error diffusion to S neighbor}\6
$\\{gamma}\K5/16$;\C{error diffusion to SE neighbor}\6
$\\{delta}\K3/16$;\C{error diffusion to E neighbor}\par
\fi

\M18. Here is the overall control of the process.
Every half\/line of the picture being output is a sequence of ASCII characters
from \.{"0"} to \.{"P"}, terminated by \.{"."}.

\Y\P$\4\X18:Output the picture\X\S$\6
\&{for} $\|j\K1\mathrel{\&{to}}\|n+1$ \1\&{do}\6
\&{begin} \37$\\{next1}[\|j]\K0.0$;\5
$\\{next2}[\|j]\K0.0$;\6
\&{end};\2\6
\&{for} $\|i\K1\mathrel{\&{to}}\|m$ \1\&{do}\6
\&{begin} \37\X19:Set the current half\/line data for the upper row of dots in
line~\|i\X;\6
$\|j\K1$;\5
$\|x\K\\{current}[1]$;\6
\1\&{repeat} \37\X16:Output one value and move to the next column\X;\6
\4\&{until}\5
$\|j>\|n$;\2\6
$\\{write\_ln}(\.{\'.\'})$;\5
\X20:Set the current half\/line data for the lower row of dots in line~\|i\X;\6
$\|j\K1$;\5
$\|x\K\\{current}[1]$;\6
\1\&{repeat} \37\X16:Output one value and move to the next column\X;\6
\4\&{until}\5
$\|j>\|n$;\2\6
$\\{write\_ln}(\.{\'.\'})$;\6
\&{end}\2\par
\U section~23.\fi

\M19. The density value for dot \|j in the upper half\/line of line~\|i is
obtained
as a weighted average of the input values in rows $\|i-1$ and~\|i, columns
\|j and~$\|j+1$. The upper half\/line is skewed to the right, so we must shift
\\{next1} and \\{next2} appropriately.

\Y\P$\4\X19:Set the current half\/line data for the upper row of dots in line~\|i%
\X\S$\6
\&{for} $\|j\K1\mathrel{\&{to}}\|n$ \1\&{do}\6
\&{begin} \37$\\{current}[\|j]\K(9\ast\|v[\|i,\39\|j]+3\ast\|v[\|i,\39\|j+1]+3%
\ast\|v[\|i-1,\39\|j]+\|v[\|i-1,\39\|j+1])/16+\\{next1}[\|j+1]$;\5
$\\{next1}[\|j]\K\\{next2}[\|j]$;\6
\&{end};\2\6
$\\{next1}[\|n+1]\K0.0$\par
\U section~18.\fi

\M20. The lower half\/line is similar, but in this case there is leftward skew;
we use rows \|i and~$\|i+1$, columns $\|j-1$ and~\|j.

\Y\P$\4\X20:Set the current half\/line data for the lower row of dots in line~\|i%
\X\S$\6
\&{for} $\|j\K1\mathrel{\&{to}}\|n$ \1\&{do}\6
\&{begin} \37$\\{current}[\|j]\K(9\ast\|v[\|i,\39\|j]+3\ast\|v[\|i,\39\|j-1]+3%
\ast\|v[\|i+1,\39\|j]+\|v[\|i+1,\39\|j-1])/16+\\{next1}[\|j]$;\5
$\\{next1}[\|j+1]\K\\{next2}[\|j]$;\6
\&{end};\2\6
$\\{next1}[1]\K0.0$\par
\U section~18.\fi

\M21. The algorithm is now complete except for the part that chooses the
closest possible dot size. A straightforward binary search works well
for this purpose:

\Y\P$\4\X21:Find \|l so that $\|d[\|l]$ is as close as possible to \|x\X\S$\6
\&{if} $\|x\L0.0$ \1\&{then}\5
$\|l\K0$\6
\4\&{else} \&{if} $\|x\G1.0$ \1\&{then}\5
$\|l\K\\{max\_l}$\6
\4\&{else} \&{begin} \37$\\{low\_l}\K0$;\5
$\\{high\_l}\K\\{max\_l}$;\C{we have $\|d[\\{low\_l}]\L\|x<\|d[\\{high\_l}]$}\6
\&{while} $\\{high\_l}-\\{low\_l}>1$ \1\&{do}\6
\&{begin} \37$\\{mid\_l}\K(\\{low\_l}+\\{high\_l})\mathbin{\&{div}}2$;\6
\&{if} $\|x\G\|d[\\{mid\_l}]$ \1\&{then}\5
$\\{low\_l}\K\\{mid\_l}$\6
\4\&{else} $\\{high\_l}\K\\{mid\_l}$;\2\6
\&{end};\2\6
\&{if} $\|x-\|d[\\{low\_l}]\L\|d[\\{high\_l}]-\|x$ \1\&{then}\5
$\|l\K\\{low\_l}$\ \&{else} $\|l\K\\{high\_l}$;\2\6
\&{end}\2\2\par
\U section~16.\fi

\M22. We had better declare the variables we've been using.

\Y\P$\4\X6:Global variables\X\mathrel{+}\S$\6
\4\|x: \37\\{real};\C{current pixel density}\6
\4\\{err}: \37\\{real};\C{difference between \|x and the best we can achieve}\6
\4\\{current}: \37\&{array} $[0\to\\{max\_n}]$ \1\&{of}\5
\\{real};\C{desired densities in current half\/line}\2\6
\4$\\{next1},\39\\{next2}$: \37\&{array} $[0\to\\{max\_n}]$ \1\&{of}\5
\\{real};\C{corrections to subsequent densities}\2\6
\4$\\{alpha},\39\\{beta},\39\\{gamma},\39\\{delta}$: \37\\{real};\C{constants
of error diffusion}\6
\4$\|l,\39\\{low\_l},\39\\{mid\_l},\39\\{high\_l}$: \37$0\to\\{max\_l}$;%
\C{trial density levels}\par
\fi

\N23.  The main program.
Now we're ready to put all the pieces together.

\Y\P$\4\X23:The main program\X\S$\6
$\\{write\_ln}(\.{\'\\input\ hf33\'})$;\5
\\{write\_ln};\6
\&{while} $\\{true}$ \1\&{do}\6
\&{begin} \37\X12:Input a picture, or terminate the program\X;\6
$\\{write\_ln}(\.{\'\\beginhalftone\'})$;\5
\X18:Output the picture\X;\6
$\\{write\_ln}(\.{\'\\endhalftone\'})$;\5
\\{write\_ln};\6
\&{end};\2\6
\4\\{cleanup\_and\_terminate}: \37\par
\U section~2.\fi

\message{app4 is next (and last!)}
\bye